import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Logger;


public class GameFrame1 extends JFrame
{
    private Boolean runFlag;
    static int redTeamUnitID;
    private final long startTimeMillis;
    //private StateObject stateObject;

    Logger logger = MyLogger.getLogger();
    private final Graphics graphics; //画笔
    private final Image buffer;  // 双缓冲图像
    private final Graphics bufferGraphics;  // 双缓冲图像的绘图上下文

    private Vector<Bullet> bullets; //存放子弹

    private final Maps maps;  // 背景图片

    private final Friends friends;  //友方飞机

    private final Enemies enemies;  //敌方飞机

    private final int windowWidth;//画板的宽度
    private final int windowHeight;//画板的高度

    private long timerClick; //计时器

    public static int getRedTeamUnitID(Team team) {
        return redTeamUnitID++;
    }

    public TcpServer getTcpServer() {
        return tcpServer;
    }

    public void setTcpServer(TcpServer tcpServer) {
        this.tcpServer = tcpServer;
    }

    TcpServer tcpServer;

    public TcpClient getTcpClient() {
        return tcpClient;
    }

    public void setTcpClient(TcpClient tcpClient) {
        this.tcpClient = tcpClient;
    }

    TcpClient tcpClient;

    //构造方法
    public GameFrame1()
    {
        if (Global.thisDeviceType == SelfType.DEVICE_TYPE_CLIENT)
        {
            //tcpClient = new TcpClient();
            setTitle("Fighting Client");
        }
        else
        {
            setTitle("Fighting Server");
        }

        startTimeMillis = System.currentTimeMillis();

        setLayout(null);
        windowWidth = 629;
        windowHeight = 990;
        setSize(windowWidth, windowHeight);
        setLocationRelativeTo(null);
        setVisible(true);
        timerClick = 0;
        runFlag = true;
        graphics = getContentPane().getGraphics();
        buffer = createImage(windowWidth, windowHeight);
        bufferGraphics = buffer.getGraphics();

        enemies = new Enemies();
        enemies.setMaxCount(8);
        enemies.setMoveSpeed(20);
        enemies.setFireSpeed(660);
        enemies.setPlaneAddSpeed(80);

        friends = new Friends();
        friends.setMaxCount(2);
        friends.setFireSpeed(20);


        maps = new Maps();
        maps.setMoveStep(3);
        maps.setCurrentY(0);

        
        FriendPlaneInitial();

        BackgroundInitial();
        BulletsInitial();
        KeyCapture();
    }
    private void BulletsInitial()
    {
        bullets = new Vector<Bullet>();

        Bullet bullet2 = new Bullet("bullet_02.png");
        Bullet bullet1 = new Bullet("bullet_01.png");
        bullet1.setType(SelfType.PLANE_TYPE_FRIEND);
        bullet2.setType(SelfType.PLANE_TYPE_ENEMY);
        bullets.add(bullet1);
        //bullets.add(bullet2);

        for (Bullet bullet: bullets)
        {
            bullet.setMoveStep(6);
        }
    }

    private void BackgroundInitial()
    {
        Vector<Plane> backgroundMaps = maps.getBackgroundMaps();

        for (int i = 0; i < 2; i++)
        {
            Plane map = new Plane("background_01.png");
            map.setWidth(windowWidth);
            map.setHeight(windowHeight);
            map.setMoveStep(3);
            backgroundMaps.add(map);
        }
    }

    private void EnemyPlaneAddOne()
    {
        enemies.enemyAdd(windowWidth);
    }

    //友方飞机初始化
    private void FriendPlaneInitial()
    {
        Vector<Plane>  friendPlanes = friends.getFriendsPlanes();

        Plane plane1 = new Plane("Plane0" + 1 + ".png");
        Plane plane2 = new Plane("Plane0" + 2 + ".png");
        plane1.setFireType(SelfType.BULLET_MOVE_TYPE_CIRCLE);
        plane2.setFireType(SelfType.BULLET_MOVE_TYPE_LINE);
        friendPlanes.add(plane1);
        friendPlanes.add(plane2);

        int i = 1;
        for (Plane friendPlane : friendPlanes)
        {
            //friendPlanes[i].imageSet("Plane0" + (i+1) + ".png");
            friendPlane.setCurrentX(windowWidth * i++ / 3);
            friendPlane.setCurrentY(windowHeight - 200);
            friendPlane.setMoveStep(3);
            friendPlane.setModelWidth(128);
            friendPlane.setModelHeight(128);
            friendPlane.setType(SelfType.PLANE_TYPE_FRIEND); //friend
        }
    }

    public void Player1KeyboardHandle(int keyCode, int playerID)
    {
        Vector<Plane>  friendPlanes = friends.getFriendsPlanes();
        switch (keyCode)
        {
            /**
             * Player1 or Server
             */
            case KeyEvent.VK_UP:
                friendPlanes.get(playerID).moveUp();
                break;

            case KeyEvent.VK_DOWN:
                friendPlanes.get(playerID).moveDown();
                break;

            case KeyEvent.VK_LEFT:
                friendPlanes.get(playerID).moveLeft();
                break;

            case KeyEvent.VK_RIGHT:
                friendPlanes.get(playerID).moveRigth();
                break;

            case KeyEvent.VK_Q:
                runFlag = false;
                break;

            default:
                System.out.println("KeyCode error!");break;
        }
    }

    public void Player2KeyboardHandle(int keyCode, int playerID)
    {
        logger.info("ClientKeyboardHandle");
        Vector<Plane>  friendPlanes = friends.getFriendsPlanes();
        switch (keyCode)
        {
            /**
             * Player2 or Client
             */
            case KeyEvent.VK_W:
                friendPlanes.get(playerID).moveUp();
                break;

            case KeyEvent.VK_S:
                friendPlanes.get(playerID).moveDown();
                break;

            case KeyEvent.VK_A:
                friendPlanes.get(playerID).moveLeft();
                break;

            case KeyEvent.VK_D:
                friendPlanes.get(playerID).moveRigth();
                break;

            default:
                System.out.println("KeyCode error!"); break;
        }
    }

    //读取键盘输入
    public void KeyCapture()
    {
        Vector<Plane>  friendPlanes = friends.getFriendsPlanes();
        this.addKeyListener(new KeyAdapter()
        {
            public void keyPressed(KeyEvent e)
            {
                if (friendPlanes.size() == 0)
                {
                    runFlag = false;
                    return;
                }

                int keyCode = e.getKeyCode();
                System.out.println("keyCode: " + keyCode);

                Player1KeyboardHandle(keyCode, 0);

                // 双电脑，此电脑为服务器
                if (SelfType.NET_TYPE_TWO_PLAYER == Global.netMode && Global.thisDeviceType == SelfType.DEVICE_TYPE_SERVER)
                {
                    return;
                }
                // 双电脑，此电脑为客户端
                else if (SelfType.NET_TYPE_TWO_PLAYER == Global.netMode && Global.thisDeviceType == SelfType.DEVICE_TYPE_CLIENT)
                {
                    Player2KeyboardHandle(keyCode, 1);
                }
                // 单电脑，此电脑为服务器
                else if (SelfType.NET_TYPE_SINGLE == Global.netMode && Global.thisDeviceType == SelfType.DEVICE_TYPE_SERVER)
                {
                    Player2KeyboardHandle(keyCode, 1);
                }
            }
        });
    }

    //判断子弹是否击中飞机
    private Boolean Hit(Bullet bullet, Plane plane)
    {
        int bulletType = bullet.getType();
        int planeType = plane.getType();
        int bulletX = bullet.getCurrentX();
        int bulletY = bullet.getCurrentY();
        int planeX = plane.getCurrentX();
        int planeY = plane.getCurrentY();
        int planeWidth = plane.getModelWidth();
        int planeHeight = plane.getModelHeight();
        //System.out.println("planeType=" + planeType + ", planeX=" + planeX + ", planeY=" + planeY + ", planeWidth=" + planeWidth + ", planeHeight=" + planeHeight);
        //System.out.println("bulletType=" + bulletType + ", bulletX=" + bulletX + ", bulletY=" + bulletY);
        return bulletX > planeX && bulletX < planeX + planeWidth
                && bulletY > planeY && bulletY < planeY + planeHeight;
    }

    public void RunClient()
    {
        //logger.info("");
        if (!runFlag)
        {
            return;
        }

        StateObject stateObjectReceive = null;
        Vector<Item> planes = new Vector<>();
        Vector<Item> bullets = new Vector<>();

        if (Global.thisDeviceType == SelfType.DEVICE_TYPE_CLIENT)
        {
            //客户端接收从服务器端发送过来的状态数据
            stateObjectReceive = tcpClient.receive();
            planes = stateObjectReceive.getPlanes();
            bullets = stateObjectReceive.getBullets();
            logger.info(planes.toString());
            logger.info(bullets.toString());
            maps.setCurrentY(stateObjectReceive.getCurrentY());
        }
        // System.out.println("timerClick=" + timerClick + ", backgroundY=" + backgroundY);
        //计数器增加
        timerClick++;

        //防止背景Y的值溢出
        int backgroundY = maps.getCurrentY();
        maps.setCurrentY(backgroundY >= windowHeight ? 0 : backgroundY);
        // background

        //两张图片移动拼成窗口背景
        Vector<Plane> backgroundMaps = maps.getBackgroundMaps();
        bufferGraphics.drawImage(backgroundMaps.get(0).getImage(), 0, backgroundY, windowWidth, windowHeight, this);
        bufferGraphics.drawImage(backgroundMaps.get(1).getImage(), 0, backgroundY - windowHeight, windowWidth, windowHeight, this);

        Vector<Plane>  enemyPlanes = enemies.getEnemyPlanes();

        Vector<Plane>  friendPlanes = friends.getFriendsPlanes();

        //客户端准备把本地Player2操作的数据打包发送给服务器端
        StateObject stateObjectSend = new StateObject("Sent from client: ");
        Vector<Item> itemVectorPlanes = stateObjectSend.getPlanes();
        //stateObjectSend.setCurrentY(111);

        Plane friendPlane = friendPlanes.get(1);
        int x = friendPlane.getCurrentX();
        int y = friendPlane.getCurrentY();
        Item item1 = new Item();
        copy(item1, friendPlane);
        itemVectorPlanes.add(item1);
        bufferGraphics.drawImage(friendPlane.getImage(), x, y, null);

        for (Item item: planes)
        {
            Plane plane = new Plane(item.getName());

            bufferGraphics.drawImage(plane.getImage(), item.getCurrentX(), item.getCurrentY(), null);
        }

        for (Item item: bullets)
        {
            Bullet bullet = new Bullet(item.getName());
            bufferGraphics.drawImage(bullet.getImage(), item.getCurrentX(), item.getCurrentY(), 10, 10, null);
        }
        graphics.drawImage(buffer, 0, 0, null);
        tcpClient.send(stateObjectSend);
    }

    public void copy(Item dest, Plane source)
    {
        /*dest = source;*/

        dest.setCurrentX(source.getCurrentX());
        dest.setCurrentY(source.getCurrentY());
        dest.setType(source.getType());
        dest.setName(source.getName());
        dest.setMoveStepX(source.getMoveStep());
        dest.setMoveStepY(source.getMoveStep());
    }


    public void copy2(Item source , Plane dest)
    {
        /*dest = (Plane)source;*/

        dest.setCurrentX(source.getCurrentX());
        dest.setCurrentY(source.getCurrentY());
        dest.setType(source.getType());
        dest.setMoveStep(source.getMoveStepX());
        //dest.set(source.getMoveStepY());
    }

    public void RunServer()
    {
        long currentTimeMillis = System.currentTimeMillis();
        long timeCost = currentTimeMillis - startTimeMillis;
        if (!runFlag)
        {
            return;
        }
        StateObject stateObjectReceive = null;
        if (tcpServer.getClientCount() != 0)
        {
            stateObjectReceive = tcpServer.receive();
        }

        //这里是想让飞机在不同性能硬件的电脑可以同频率发射子弹
        //if (timeCost > timerClick * 20)
        {
            logger.info("timerClick: " + timerClick + ", time: " + timeCost / 1000 + " seconds, " + timeCost % 1000 + " milliseconds.");
            timerClick++;
        }
        //else
        {
            //return true;
        }

        if (Global.thisDeviceType == SelfType.DEVICE_TYPE_CLIENT)
        {
            StateObject stateObject1 = tcpClient.receive();
            return;
        }
        // System.out.println("timerClick=" + timerClick + ", backgroundY=" + backgroundY);
        //计数器增加
        //timerClick++;

        //防止背景Y的值溢出
        int backgroundY = maps.getCurrentY();
        maps.setCurrentY(backgroundY >= windowHeight ? 0 : backgroundY);

        //用于把服务器本地飞机、子弹、地图当前的状态打包发给客户端
        StateObject stateObject = new StateObject("Sent from server:");
        stateObject.setCurrentY(backgroundY);

        Vector<Item> itemVectorPlanes = stateObject.getPlanes();
        Vector<Item> itemVectorBullets = stateObject.getBullets();

        //两张图片移动拼成窗口背景
        Vector<Plane> backgroundMaps = maps.getBackgroundMaps();
        bufferGraphics.drawImage(backgroundMaps.get(0).getImage(), 0, backgroundY, windowWidth, windowHeight, this);
        bufferGraphics.drawImage(backgroundMaps.get(1).getImage(), 0, backgroundY - windowHeight, windowWidth, windowHeight, this);

        //不断增加
        maps.setCurrentY(maps.getMoveStep() + maps.getCurrentY());

        //将超出屏幕的子弹移除
        if (bullets.size() > 0)
        {
            Iterator<Bullet> iterator = bullets.iterator();

            while (iterator.hasNext())
            {
                Bullet bullet = iterator.next();
                int bulletY = bullet.getCurrentY();

                if (bulletY >= windowHeight || bulletY <= 0)
                {
                    iterator.remove();
                }
            }
        }

        Vector<Plane>  enemyPlanes = enemies.getEnemyPlanes();

        Vector<Plane>  friendPlanes = friends.getFriendsPlanes();

        int index = 0;
        for (Bullet bullet: bullets)
        {
            int bulletX = bullet.getCurrentX();
            int bulletY = bullet.getCurrentY();

            if (bulletY >= windowHeight || bulletY <= 0)
            {
                //bullets.remove(bullet);
                if (bullets.size() == 0)
                {
                    break;
                }
                continue;
            }

            //画出子弹
            bufferGraphics.drawImage(bullet.getImage(), bulletX, bulletY, null);

            Item item = new Item();
            copy(item, bullet);
            itemVectorBullets.add(item);
            index++;

            //分别判断友方和敌方飞机是否被击中
            if (bullet.getType() == SelfType.PLANE_TYPE_ENEMY)
            {
                for (Plane plane: friendPlanes)
                {
                    if (Hit(bullet, plane))
                    {
                        friendPlanes.remove(plane);
                        break;
                    }
                }
                bullet.moveDown();
            }
            else if (bullet.getType() == SelfType.PLANE_TYPE_FRIEND)
            {
                for (Plane plane: enemyPlanes)
                {
                    if (Hit(bullet, plane))
                    {
                        enemyPlanes.remove(plane);
                        break;
                    }

                }
                //bullet.moveUp();
                //bullet.Move(SelfType.BULLET_MOVE_TYPE_CIRCLE);
                bullet.Move();
            }
        }

        if (stateObjectReceive != null)
        {
            Vector<Item> planes = stateObjectReceive.getPlanes();

            //第一个的值是111，后边的包不是
            if (stateObjectReceive.getCurrentY() != 111 && Global.thisDeviceType == SelfType.DEVICE_TYPE_SERVER && Global.netMode == SelfType.NET_TYPE_TWO_PLAYER)
            {
                if (friendPlanes.size() > 1)
                {
                    Plane plane = friendPlanes.get(1);
                    copy2(planes.get(0), plane);
                    friendPlanes.set(1, plane);
                }

            }
        }

        //下边是获取飞机的状态，所以索引需要为0，因为使用的不同Vector
        index = 0;
        // friendPlanes
        for (Plane friendPlane : friendPlanes)
        {
            int x = friendPlane.getCurrentX();
            int y = friendPlane.getCurrentY();
            bufferGraphics.drawImage(friendPlane.getImage(), x, y, null);

            Item item = new Item();
            copy(item, friendPlane);
            itemVectorPlanes.add(item);

            //发射子弹
            if (timerClick % friends.getFireSpeed() == 0)
            {
                int fireType = friendPlane.getFireType();
                if (fireType == SelfType.BULLET_MOVE_TYPE_LINE)
                {
                    for (int i = -4; i < 4; i++)
                    {
                        Bullet bullet = new Bullet("bullet_01.png");
                        bullet.setType(SelfType.PLANE_TYPE_FRIEND);
                        bullet.setMoveStep(6);
                        bullet.setCurrentX(x + friendPlane.getModelWidth() / 3);
                        bullet.setCurrentY(y);
                        bullet.recordStartPoint();
                        bullet.setMoveArguements(new int[]{1 * i,5});
                        bullet.setMoveType(fireType);
                        bullets.add(bullet);
                    }
                }
                else if (fireType == SelfType.BULLET_MOVE_TYPE_CIRCLE)
                {
                    for (int i = 1; i < 7; i++)
                    {
                        Bullet bullet = new Bullet("bullet_01.png");
                        bullet.setType(SelfType.PLANE_TYPE_FRIEND);
                        bullet.setMoveStep(36);
                        bullet.setCurrentX(x + friendPlane.getModelWidth() / 3);
                        bullet.setCurrentY(y);
                        bullet.setStartAngle(i * 30);
                        bullet.recordStartPoint();
                        bullet.setMoveArguements(new int[]{2 * i,5}); //1, 2, 3
                        bullet.setMoveType(fireType);
                        bullets.add(bullet);
                    }
                }

                if (bullets.size() > 30)
                {
                    bullets.remove(0);
                }
            }
        }

        if (timerClick % enemies.getPlaneAddSpeed() == 0) //enemy plane added per count.
        {
            EnemyPlaneAddOne();
        }

        if (enemyPlanes.size() > enemies.getMaxCount()) // enemy plans count must less than this count
        {
            enemyPlanes.remove(0);
        }

        //发射子弹
        for (Plane enemyPlane : enemyPlanes)
        {
            int x = enemyPlane.getCurrentX();
            int y = enemyPlane.getCurrentY();
            bufferGraphics.drawImage(enemyPlane.getImage(), x, y, null);
            //System.out.println(x +", y: "+ y);

            Item item = new Item();
            copy(item, enemyPlane);
            itemVectorPlanes.add(item);

            if (timerClick % enemies.getFireSpeed() == 0)
            {
                Bullet bullet = new Bullet("bullet_02.png");
                bullet.setType(SelfType.PLANE_TYPE_ENEMY); //0
                bullet.setMoveStep(9);
                bullet.setCurrentX(x + enemyPlane.getModelWidth() / 3);
                bullet.setCurrentY(y);
                bullets.add(bullet);
            }

            enemyPlane.moveDown();

            //敌方飞机自动向友方飞机靠拢
            if (timerClick % enemies.getMoveSpeed() == 0)
            {
                if (enemyPlane.getCurrentX() < friendPlanes.get(0).getCurrentX()) {
                    enemyPlane.moveRigth();
                }
                else
                {
                    enemyPlane.moveLeft();
                }
            }
        }
        graphics.drawImage(buffer, 0, 0, null);

        logger.info("planes size: " + stateObject.getPlanes().size() + ", bullets size:" + stateObject.getBullets().size());
        tcpServer.send(stateObject);
    }
}

